package cn.bearspark.framework.redis.starter.buffer;

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SessionCallback;
import org.springframework.data.redis.core.script.DefaultRedisScript;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.List;
import java.util.function.Consumer;

/**
 * Redis 缓存器的抽象父类 TODO 之后看看能否使用模版方法模式统一缓存的查询过程
 *
 * @author f
 */
public abstract class RedisBuffer {

    protected final RedisTemplate<String, Object> redisTemplate;

    public RedisBuffer(RedisTemplate<String, Object> redisTemplate) {
        this.redisTemplate = redisTemplate;
    }

    /**
     * 执行一段复杂的逻辑
     *
     * @param operation 复杂的逻辑
     */
    protected void execute(Consumer<RedisOperations<String, Object>> operation) {
        redisTemplate.execute(new SessionCallback<>() {
            @Override
            public <K, V> Void execute(RedisOperations<K, V> operations) throws DataAccessException {
                operation.accept((RedisOperations<String, Object>) operations);
                return null;
            }
        });
    }

    /**
     * 执行一段复杂的逻辑，通过 Redis 的 Pipeline 技术优化，不能返回值
     *
     * @param operation 复杂的逻辑
     */
    protected void executePipelined(Consumer<RedisOperations<String, Object>> operation) {
        redisTemplate.executePipelined(new SessionCallback<>() {
            @Override
            public <K, V> Void execute(RedisOperations<K, V> operations) throws DataAccessException {
                operation.accept((RedisOperations<String, Object>) operations);
                return null;
            }
        });
    }

    /**
     * 执行 lua 脚本
     *
     * @param scriptPath 脚本的路径
     * @param keys       键的集合
     * @param args       参数
     */
    protected void executeScript(String scriptPath, List<String> keys, Object... args) {
        // 加载 Lua 脚本文件
        Resource resource = new ClassPathResource(scriptPath);
        StringBuilder scriptBuilder = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) {
            String line;
            while ((line = reader.readLine()) != null) {
                scriptBuilder.append(line).append("\n");
            }
        } catch (IOException e) {
            throw new RuntimeException("Failed to read Lua script file", e);
        }

        // 创建 RedisScript 对象
        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
        redisScript.setScriptText(scriptBuilder.toString());
        redisScript.setResultType(Long.class);

        // 传递参数，执行脚本
        redisTemplate.execute(redisScript, keys, args);
    }

    /**
     * 将指定的对象转换成 Long 类型的数
     *
     * @param obj 指定的对象
     * @return Long 类型的数
     */
    protected Long objToLong(Object obj) {
        if (obj instanceof Integer) {
            return Long.valueOf((Integer) obj);
        }
        return (Long) obj;
    }

    /**
     * 将指定的对象转换成 Integer 类型的数
     *
     * @param obj 指定的对象
     * @return Integer 类型的数
     */
    protected Integer objToInteger(Object obj) {
        return (Integer) obj;
    }

    /**
     * 删除指定匹配模式的键对应的缓存
     *
     * @param pattern 指定的匹配模式
     */
    protected void cleanWithPattern(String pattern) {
        execute(operations -> operations.delete(operations.keys(pattern)));
    }
}
